﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Hardanger.Model;
using System.ComponentModel;
using System.Windows.Threading;
using Hardanger.Features.ServerFuzzer;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Hardanger.Features.ServerFuzzer.DetectionEngine;
using Hardanger.Features.ServerFuzzer.ServerFuzzerEngine;

namespace Hardanger.ViewModel
{
    public class ServerFuzzerViewModel : BaseViewModel 
    {
        #region Fields

        private static ServerFuzzerViewModel _current;
        private static Dictionary<int, ServerFuzzerViewModel> _serverFuzzerViewModelList;

        private int _fiddlerId;
        private HardangerSession _hardangerSession;
        private Dictionary<ServerFuzzingType, ServerFuzzerConfigurationSetting> _fuzzerConfiguration;
        private ObservableCollection<string> _detectionEngines;

        private RelayCommand _toggleFuzzerCommand;
        private RelayCommand _addDetectionEngineCommand;
        private RelayCommand _removeDetectionEngineCommand;
        private RelayCommand _addAllDetectionEnginesCommand;
        private RelayCommand _removeAllDetectionEnginesCommand;
        private string _dropDownSelectedDetectionEngine;
        private string _listBoxSelectedDetectionEngine;
        private string _fuzzerButtonText = "Start Fuzzing";
        private long _iterations;
        private long _sessionResultCount;
        private int _currentNumberOfThreads;

        private bool _stripIfModifiedSince = true;
        private bool _stripPragmaNoCache = true;

        #endregion //Fields

        #region Constructor

        public ServerFuzzerViewModel()
        {
        }

        public ServerFuzzerViewModel(HardangerSession hardangerSession)
        {
            _hardangerSession = hardangerSession;
            _fiddlerId = _hardangerSession.FiddlerId;
            ServerFuzzerViewModelList.Add(_fiddlerId, this);
            Current = this;
            FuzzingEnabled = true;
            ServerFuzzerMasterEngine.Current.PropertyChanged += new PropertyChangedEventHandler(MasterFuzzer_PropertyChanged);
            MaximumThreadsAvailable = 200;
            MaxThreadCount = 10;
            RequestTimeOut = 180000;

            //_fuzzerConfiguration = new Dictionary<ServerFuzzingType, Dictionary<string, ServerFuzzingItem>>();
            _fuzzerConfiguration = new Dictionary<ServerFuzzingType, ServerFuzzerConfigurationSetting>();
            PopulateConfigurationItems(ServerFuzzingType.Headers, HttpHeaders);
            PopulateConfigurationItems(ServerFuzzingType.GetParameters, GetParameters.Parameters);
            PopulateConfigurationItems(ServerFuzzingType.PostParameters, PostParameters.Parameters);
            
        }

        #endregion //Constructor

        #region ServerFuzzerMasterEngine Exposed Properties

        public int MaxThreadCount
        {
            get { return ServerFuzzerMasterEngine.Current.MaxThreads; }
            set { ServerFuzzerMasterEngine.Current.MaxThreads = value;
            }
        }
        public int RequestPause
        {
            get { return ServerFuzzerMasterEngine.Current.RequestPause; }
            set { ServerFuzzerMasterEngine.Current.RequestPause = value; }
        }
        public int RequestTimeOut
        {
            get { return ServerFuzzerMasterEngine.Current.RequestTimeOut; }
            set { ServerFuzzerMasterEngine.Current.RequestTimeOut = value; }
        }

        public long Iterations
        {
            get { return ServerFuzzerMasterEngine.Current.Iterations; }
            private set 
            { 
                _iterations = value;
                NotifyPropertyChanged("Iterations");
            }
        }
        public long SessionResultsCount
        {
            get { return _sessionResultCount;}
            set
            {
                _sessionResultCount = value;
                NotifyPropertyChanged("SessionResultsCount");
            }
        }

        #endregion //ServerFuzzerMasterEngine Exposed Properties

        #region ViewModel Properties

        public static ServerFuzzerViewModel Current
        {
            get
            {
                if (_current == null)
                {
                    return new ServerFuzzerViewModel();
                }
                return _current;
            }
            set
            {
                _current = value;
            }
        }
        public static Dictionary<int, ServerFuzzerViewModel> ServerFuzzerViewModelList
        {
            get
            {
                if (_serverFuzzerViewModelList == null)
                {
                    _serverFuzzerViewModelList = new Dictionary<int, ServerFuzzerViewModel>();
                }
                return _serverFuzzerViewModelList;
            }
        }

        public string DropDownSelectedDetectionEngine
        {
            get { return _dropDownSelectedDetectionEngine; }
            set
            {
                _dropDownSelectedDetectionEngine = value;
                NotifyPropertyChanged("DropDownSelectedDetectionEngine");
            }
        }
        public string ListBoxSelectedDetectionEngine
        {
            get { return _listBoxSelectedDetectionEngine; }
            set
            {
                _listBoxSelectedDetectionEngine = value;
                NotifyPropertyChanged("ListBoxSelectedDetectionEngine");
            }
        }
        public int Id
        {
            get
            {
                return _fiddlerId;
            }
        }
        public HardangerSession HardangerSession
        {
            get
            {
                return _hardangerSession;
            }
        }
        public Dictionary<String, String> HttpHeaders
        {
            get
            {
                return _hardangerSession != null ? _hardangerSession.Headers : null;
            }
        }
        public HttpGet GetParameters
        {
            get
            {
                return _hardangerSession != null ? _hardangerSession.Get : null;
            }
        }
        public HttpPost PostParameters
        {
            get
            {
                return _hardangerSession != null ? _hardangerSession.Post : null;
            }
        }
        public Dictionary<ServerFuzzingType, ServerFuzzerConfigurationSetting> FuzzerConfiguration
        {
            get
            {
                return _fuzzerConfiguration;
            }
        }
        public ObservableCollection<string> DetectionEngines
        {
            get
            {
                if (_detectionEngines == null)
                    _detectionEngines = DetectionEngineFactory.GetAllDetectionEngines();
                return _detectionEngines;
            }
        }
        public ObservableCollection<string> SelectedDetectionEngines 
        {
            get { return ServerFuzzerMasterEngine.Current.SelectedDetectionEngines; }
        }
        public bool FuzzingEnabled { get; set; }
        public string FuzzerButtonText 
        { 
            get { return _fuzzerButtonText;  }
            set 
            { 
                _fuzzerButtonText = value;
                NotifyPropertyChanged("FuzzerButtonText");
            }
        }
        public ICommand ToggleFuzzerCommand
        {
            get
            {
                if (_toggleFuzzerCommand == null)
                {
                    _toggleFuzzerCommand = new RelayCommand(
                        param => this.ToggleFuzzer()
                        );
                }
                return _toggleFuzzerCommand;
            }
        }
        public ICommand AddDetectionEngineCommand
        {
            get
            {
                if (_addDetectionEngineCommand == null)
                    _addDetectionEngineCommand = new RelayCommand(r => AddDetectionEngine());
                return _addDetectionEngineCommand;
            }
        }
        public ICommand RemoveDetectionEngineCommand
        {
            get
            {
                if (_removeDetectionEngineCommand == null)
                    _removeDetectionEngineCommand = new RelayCommand(r => RemoveDetectionEngine());
                return _removeDetectionEngineCommand;
            }
        }
        public ICommand AddAllDetectionEnginesCommand
        {
            get 
            {
                if (_addAllDetectionEnginesCommand == null)
                    _addAllDetectionEnginesCommand = new RelayCommand(r => AddAllDetectionEngines());
                return _addAllDetectionEnginesCommand;

            }
        }
        public ICommand RemoveAllDetectionEnginesCommand
        {
            get
            {
                if (_removeAllDetectionEnginesCommand == null)
                    _removeAllDetectionEnginesCommand = new RelayCommand(r => RemoveAllDetectionEngines());
                return _removeAllDetectionEnginesCommand;
            }
        }
        public int CurrentNumberOfThreads
        {
            get { return _currentNumberOfThreads; }
            set
            {
                _currentNumberOfThreads = value;
                NotifyPropertyChanged("CurrentNumberOfThreads");
            }
        }
        public int MaximumThreadsAvailable { get; set; }

        public bool StripIfModifiedSince
        {
            get { return ServerFuzzerMasterEngine.Current.StripIfModifiedSince; }
            set { ServerFuzzerMasterEngine.Current.StripIfModifiedSince = value; }
        }

        public bool StripPragmaNoCache
        {
            get { return ServerFuzzerMasterEngine.Current.StripPragmaNoCache; }
            set { ServerFuzzerMasterEngine.Current.StripPragmaNoCache = value; }
        }

        #endregion //ViewModel Properties

        #region Private Functions

        private void PopulateConfigurationItems(ServerFuzzingType sft, Dictionary<String, String> col)
        {
            _fuzzerConfiguration[sft] = new ServerFuzzerConfigurationSetting();
            _fuzzerConfiguration[sft].Name = sft.ToString();
            _fuzzerConfiguration[sft].ConfigurationItems = new Dictionary<string, ServerFuzzingItem>();

            foreach (KeyValuePair<String, String> h in col)
            {
                _fuzzerConfiguration[sft].ConfigurationItems.Add(h.Key,
                    new ServerFuzzingItem()
                    {
                        Enabled = false
                    }
                );
            }
        }
        private void RemoveAllDetectionEngines()
        {
            SelectedDetectionEngines.Clear();
        }
        private void AddAllDetectionEngines()
        {
            foreach (var engine in DetectionEngines)
                if (!SelectedDetectionEngines.Contains(engine))
                    SelectedDetectionEngines.Add(engine);
        }
        private void AddDetectionEngine()
        {
            if (!SelectedDetectionEngines.Contains(DropDownSelectedDetectionEngine))
                SelectedDetectionEngines.Add(DropDownSelectedDetectionEngine);
        }
        private void RemoveDetectionEngine()
        {
            SelectedDetectionEngines.Remove(ListBoxSelectedDetectionEngine);
        }

        #endregion //Private Functions

        #region Public Functions

        static public void SetCurrent(HardangerSession hardangerSession)
        {
            // this if makes the clean button work (since hardangerSession is null when we clear the list)
            if (hardangerSession != null)
            {
                if (_serverFuzzerViewModelList != null && _serverFuzzerViewModelList.ContainsKey(hardangerSession.FiddlerId))
                {
                    Current = _serverFuzzerViewModelList[hardangerSession.FiddlerId];
                }
                else
                {
                    //ServerFuzzerViewModel sfvm = 
                    new ServerFuzzerViewModel(hardangerSession);
                }
            }

        }

        public void ToggleFuzzer()
        {
            if (FuzzingEnabled)
            {
                FuzzerButtonText = "Stop Fuzzing";
                FuzzingEnabled = false;
                HardangerViewModel.Current.FuzzingSessionId = HardangerViewModel.Current.SelectedSession.FiddlerId;
                ServerFuzzerMasterEngine.Current.MaxThreads = MaxThreadCount;
                ServerFuzzerMasterEngine.Current.Start(HardangerSession.FiddlerId);
            }
            else
            {
                ServerFuzzerMasterEngine.Current.Stop();
                HardangerViewModel.Current.FuzzingSessionId = 0;
                FuzzerButtonText = "Start Fuzzing";
                FuzzingEnabled = true;
            }
        }

        void MasterFuzzer_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Iterations":
                    Iterations = ServerFuzzerMasterEngine.Current.Iterations;
                    break;
                case "CurrentNumberOfThreads":
                    CurrentNumberOfThreads = ServerFuzzerMasterEngine.Current.CurrentNumberOfThreads;
                    break;
                case "CurrentSessionResultCount":
                    SessionResultsCount = ServerFuzzerMasterEngine.Current.CurrentSessionResultCount;
                    break;
            }
        }

        #endregion //Public Functions
    }
}
